#include "linux/device.h"
#include "linux/slab.h"
#include "linux/of_device.h"
#include "linux/of_address.h"
#include "linux/of.h"
#include "linux/printk.h"
#include "linux/of_device.h"
#include "linux/of_address.h"
#include "linux/kernel.h"
#include "linux/of_platform.h"
#include "linux/platform_device.h"

 struct of_device_id of_default_bus_match_table[] = {
	{ .compatible = "simple-bus", },
	{ .compatible = "simple-mfd", },
	{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA
	{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
	{} /* Empty terminated list */
};

struct of_dev_auxdata *of_dev_lookup( struct of_dev_auxdata *lookup,
                                     struct device_node *np)
{
    struct of_dev_auxdata *auxdata;
    struct resource res;
    int compatible = 0;

    if (!lookup)
        return NULL;

    auxdata = lookup;
    for (; auxdata->compatible; auxdata++)
    {
        if (!of_device_is_compatible(np, auxdata->compatible))
            continue;
        compatible++;
        if (!of_address_to_resource(np, 0, &res))
            if (res.start != auxdata->phys_addr)
                continue;
        printk("%s: devname=%s\n", np->full_name, auxdata->name);
        return auxdata;
    }

    if (!compatible)
        return NULL;

    /* Try compatible match if no phys_addr and name are specified */
    auxdata = lookup;
    for (; auxdata->compatible; auxdata++)
    {
        if (!of_device_is_compatible(np, auxdata->compatible))
            continue;
        if (!auxdata->phys_addr && !auxdata->name)
        {
            printk("%s: compatible match\n", np->full_name);
            return auxdata;
        }
    }

    return NULL;
}

static int __of_device_is_compatible( struct device_node *device,
                                     char *compat, char *type, char *name)
{
    struct property *prop;
    char *cp;
    int index = 0, score = 0;

    /* Compatible match has highest priority */
    if (compat && compat[0])
    {
        prop = __of_find_property(device, "compatible", NULL);
        for (cp = of_prop_next_string(prop, NULL); cp;
             cp = of_prop_next_string(prop, cp), index++)
        {
            if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
            {
                score = INT_MAX / 2 - (index << 2);
                break;
            }
        }
        if (!score)
            return 0;
    }

    /* Matching type is better than matching name */
    if (type && type[0])
    {
        if (!device->type || of_node_cmp(type, device->type))
            return 0;
        score += 2;
    }

    /* Matching name is a bit better than not */
    if (name && name[0])
    {
        if (!device->name || of_node_cmp(name, device->name))
            return 0;
        score++;
    }

    return score;
}


/** Checks if the given "compat" string matches one of the strings in
 * the device's "compatible" property
 */
int of_device_is_compatible( struct device_node *device, char *compat)
{
    //unsigned long flags;
    int res;

    //raw_spin_lock_irqsave(&devtree_lock, flags);
    res = __of_device_is_compatible(device, compat, NULL, NULL);
    //raw_spin_unlock_irqrestore(&devtree_lock, flags);
    return res;
}


struct of_device_id *__of_match_node( struct of_device_id *matches, struct device_node *node)
{
    struct of_device_id *best_match = NULL;
    int score, best_score = 0;

    if (!matches)
        return NULL;

    for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++)
    {
        score = __of_device_is_compatible(node, matches->compatible,
                                          matches->type, matches->name);
        if (score > best_score)
        {
            best_match = matches;
            best_score = score;
        }
    }

    return best_match;
}

struct of_device_id *of_match_node( struct of_device_id *matches,  struct device_node *node)
{
    struct of_device_id *match;
    //unsigned long flags;

    //raw_spin_lock_irqsave(&devtree_lock, flags);
    match = __of_match_node(matches, node);
    //raw_spin_unlock_irqrestore(&devtree_lock, flags);
    return match;
}

void of_device_make_bus_id(struct device *dev)
{
    struct device_node *node = dev->of_node;
    uint32_t *reg;
    uint64_t addr;

    dev->init_name = node->name;
    return;

    /* Construct the name, using parent nodes if necessary to ensure uniqueness */
    while (node->parent)
    {
        /*
         * If the address can be translated, then that is as much
         * uniqueness as we need. Make it the first component and return
         */
        reg = of_get_property(node, "reg", NULL);
        if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR)
        {
            dev_set_name(dev, dev_name(dev) ? "%lx.%s:%s" : "%lx.%s",
                         (unsigned long)addr, node->name,
                         dev_name(dev));
            return;
        }

        /* format arguments only used if dev_name() resolves to NULL */
        dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
                     strrchr(node->full_name, '/') + 1, dev_name(dev));
        node = node->parent;
    }
}


/*
 * 根据设备树节点 (struct device_node) 创建并初始化一个 platform_device
 * np: 设备树节点指针，描述硬件设备
 * bus_id: 总线标识符（可选，若为 NULL 则自动生成）
 * parent: 父设备指针（通常为 platform_bus）
 * 
 * 返回值: 成功返回初始化后的 platform_device 指针，失败返回 NULL
 */
struct platform_device *of_device_alloc(struct device_node *np,
                                        char *bus_id,
                                        struct device *parent)
{
    struct platform_device *dev;
    int rc, i, num_reg = 0, num_irq;
    struct resource *res, temp_res;

    // 分配一个未初始化的 platform_device 结构体
    dev = platform_device_alloc("", -1);
    if (!dev)
        return NULL;

    //统计设备树节点中的资源数量
    // - num_reg: 地址资源（如寄存器空间）的数量
    // - num_irq: 中断资源的数量
    while (of_address_to_resource(np, num_reg, &temp_res) == 0)
        num_reg++;
    num_irq = of_irq_count(np);

    //为资源分配内存（地址资源 + 中断资源）
    if (num_irq || num_reg)
    {
        res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
        if (!res)
        {
            platform_device_put(dev);
            return NULL;
        }

        // 将资源绑定到 platform_device
        dev->num_resources = num_reg + num_irq;
        dev->resource = res;

        // 填充地址资源（如寄存器基地址、长度等）
        for (i = 0; i < num_reg; i++, res++)
        {
            rc = of_address_to_resource(np, i, res);
            if (rc ==0)
            {

            }
            //WARN_ON(rc);
        }

        // 填充中断资源（如中断号、触发类型等）
        // 若实际映射的中断数不等于预期值，输出警告
        if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
            printk("not all legacy IRQ resources mapped for %s\n", np->name);
    }

    // 关联设备树节点到 platform_device
    dev->dev.of_node = of_node_get(np); // 增加节点引用计数
    //dev->dev.fwnode = &np->fwnode;
    dev->dev.parent = parent ? parent : &platform_bus; //设置父设备（默认为 platform_bus）

    // 设置设备名称
    if (bus_id)
        dev_set_name(&dev->dev, "%s", bus_id); // 使用提供的 bus_id
    else
        of_device_make_bus_id(&dev->dev); // 自动生成名称

    return dev;
}

static struct platform_device *of_platform_device_create_pdata(
    struct device_node *np,
    char *bus_id,
    void *platform_data,
    struct device *parent)
{
    struct platform_device *dev;

    /* 检查设备是否可用：
     * 1. of_device_is_available() 检查 status 属性是否为 "okay"
     * 2. of_node_test_and_set_flag() 设置 OF_POPULATED 标志（防止重复创建）
     */
    if (!of_device_is_available(np) ||
        of_node_test_and_set_flag(np, OF_POPULATED))
        return NULL;

    // 分配 platform_device 结构体：
    // of_device_alloc() 会自动处理设备树节点到设备的绑定
    dev = of_device_alloc(np, bus_id, parent);
    if (!dev)
        goto err_clear_flag;

    dev->dev.bus = &platform_bus_type;
    dev->dev.platform_data = platform_data;
    //of_dma_configure(&dev->dev, dev->dev.of_node);
    //of_msi_configure(&dev->dev, dev->dev.of_node);

    // 将设备添加到内核设备模型：
    //失败时需回滚资源分配
    if (of_device_add(dev) != 0)
    {
        //of_dma_deconfigure(&dev->dev);
        platform_device_put(dev);
        goto err_clear_flag;
    }

    return dev;

err_clear_flag:
    // 清除 OF_POPULATED 标志，允许后续重新创建设备
    of_node_clear_flag(np, OF_POPULATED);
    return NULL;
}

/*
 * 递归创建平台总线及其子设备
 * bus: 当前处理的设备树总线节点
 * matches: 设备匹配表（用于驱动匹配）
 * lookup: 辅助数据表（用于覆盖设备属性）
 * parent: 父设备指针
 * strict: 是否启用严格模式（要求必须有compatible属性）
 *
 * 该函数递归遍历设备树节点，创建平台设备并绑定到内核驱动模型
 */
static int of_platform_bus_create(struct device_node *bus,
                                  struct of_device_id *matches,
                                  struct of_dev_auxdata *lookup,
                                  struct device *parent, int strict)
{
    struct of_dev_auxdata *auxdata; // 辅助数据指针
    struct device_node *child; // 子节点指针
    struct platform_device *dev; // 创建的平台设备
    char *bus_id = NULL; // 总线ID（可被辅助数据覆盖）
    void *platform_data = NULL; // 平台数据指针
    int rc = 0; // 返回码

    // 严格模式下检查兼容性属性
    if (strict && (!of_get_property(bus, "compatible", NULL)))
    {
        printk("%s() - skipping %s, no compatible prop\n", __func__, bus->full_name);
        return 0;
    }

    // 检查是否已处理过该总线
    if (of_node_check_flag(bus, OF_POPULATED_BUS))
    {
        printk("%s() - skipping %s, already populated\n", __func__, bus->full_name);
        return 0;
    }

    // 查找辅助数据
    auxdata = of_dev_lookup(lookup, bus);
    if (auxdata)
    {
        bus_id = auxdata->name;
        platform_data = auxdata->platform_data;
    }

    // 处理ARM PrimeCell总线（特殊处理）
    if (of_device_is_compatible(bus, "arm,primecell"))
    {
        /*
         * Don't return an error here to keep compatibility with older
         * device tree files.
         */
        //of_amba_device_create(bus, bus_id, platform_data, parent);
        return 0;
    }

    // 创建平台设备
    dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
    if (!dev || !of_match_node(matches, bus)) // 创建失败或匹配失败则退出
        return 0;

    // 递归处理所有子节点
    for_each_child_of_node(bus, child)
    {
        printk("   create child: %s\n", child->full_name);
        rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
        if (rc)
        {
            of_node_put(child); // 释放节点引用
            break;
        }
    }

    // 标记总线为已处理 
    of_node_set_flag(bus, OF_POPULATED_BUS);
    return rc;
}


/*
 * 根据设备树节点创建平台设备和总线
 * root: 设备树的起始节点（若为NULL则使用根节点）
 * matches: 设备匹配表，用于过滤和匹配设备树节点
 * lookup: 辅助数据，用于设备初始化时的额外配置
 * parent: 父设备指针，用于设备层级关系
 *
 * 此函数遍历指定根节点的所有子节点，为每个兼容的节点创建对应的平台设备。
 * 主要用于系统启动时初始化设备树中定义的平台设备。
 */
int of_platform_populate(struct device_node *root,
                         struct of_device_id *matches,
                         struct of_dev_auxdata *lookup,
                         struct device *parent)
{
    struct device_node *child;
    int rc = 0;

    // 确定要处理的设备树根节点
    // 如果传入root为NULL，则获取全局设备树根节点("/")
    // of_node_get() 增加节点引用计数，防止被提前释放
    root = root ? of_node_get(root) : of_find_node_by_path("/");
    if (!root)
        return -1;

    printk("%s()\n", __func__);
    printk(" starting at: %s\n", root->full_name);

    // 遍历所有子节点并创建设备
    // for_each_child_of_node 宏遍历root节点的每个直接子节点
    for_each_child_of_node(root, child)
    {
        // of_platform_bus_create() 是核心创建函数，返回0表示成功
        rc = of_platform_bus_create(child, matches, lookup, parent, true);
        if (rc)
        {
            of_node_put(child);
            break;
        }
    }
    
    // OF_POPULATED_BUS 标志表示该总线下的设备已创建
    of_node_set_flag(root, OF_POPULATED_BUS);

    of_node_put(root);
    return rc;
}

int of_platform_default_populate(struct device_node *root, struct of_dev_auxdata *lookup, struct device *parent)
{
    return of_platform_populate(root, of_default_bus_match_table, lookup, parent);
}

